package utils;

import utils.node.ServerNode;
import gui.ChatsPanel;
import gui.display.ServerDisplay;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.tree.DefaultMutableTreeNode;
import utils.node.RootNode;

/**
 * This is a connection to the server, handling the input and output.
 */
public class ServerConnection
{
    private final String host_;
    private final int port_;
    private final String nick_;
    private final String pass_;

    private String currentNick_;

    private Socket socket_;
    private Thread msgHandler_;
    private Runnable runnable_;
    private BufferedWriter bw_;
    private BufferedReader br_;
    
    private final ServerDisplay display_ = new ServerDisplay( this );
    private final Lock lock_ = new Lock();
    private final LinkedList<Chat> chats_ = new LinkedList<Chat>();
    
    private final ServerNode node_ = new ServerNode(this);

    public ServerConnection( String host, int port, String nick, String pass, ChatsPanel chatPanel )
    {
        host_ = host;
        port_ = port;
        nick_ = nick;
        pass_ = pass;
    }

    public ServerConnection( String host, int port, String nick, ChatsPanel chatPanel )
    {
        host_ = host;
        port_ = port;
        nick_ = nick;
        currentNick_ = nick;
        pass_ = null;
    }

    public void connect()
    {
        try
        {
            // If we are already connected, do nothing
            // TODO: Should reconnect?
            if( socket_ != null )
                return;
            
            socket_ = new Socket( host_, port_ );
            bw_ = new BufferedWriter( new OutputStreamWriter( socket_.getOutputStream(), "ISO-8859-1" ) );
            //_br = new BufferedReader( new InputStreamReader( _socket.getInputStream(), "UTF8" ) );
            br_ = new BufferedReader( new InputStreamReader( socket_.getInputStream(), "ISO-8859-1" ) );
            runnable_ = new ServerThreadRunnable( this );

            msgHandler_ = new Thread( runnable_ );
            msgHandler_.start();
            bw_.write( "USER dasIRC 0 * :" + nick_ + "\n" );
            bw_.write( "NICK " + nick_ + "\n" );
            bw_.flush();
        }
        catch ( IOException ex )
        {
            display_.print(  "Something wen't wrong: " + ex.getMessage() );
        }
    }

    /**
     * Disconnects from the server.
     * 
     * @param message the quit message
     */
    public void disconnect( String message )
    {
        try
        {
            bw_.write( "QUIT" + (message != null ? (" :" + message) : "") + "\n" );
            bw_.flush();
            msgHandler_.interrupt();
            System.out.println( "Disconnected from host: " + host_ );
        }
        catch ( Exception ex )
        {
            // Silence is golden
        }
    }

    /**
     * Checks wether or not we already are in the channel.
     *
     * @param channel the channel to check
     * @return true if in the chat
     */
    public final boolean isInChat( String channel )
    {
        for( Chat c : chats_ )
            if( c.getName().equalsIgnoreCase( channel ) )
                return true;
        return false;
    }

    public final void joinIfNotInChat( String channel )
    {
        if( isInChat( channel ) )
            return;

        Chat c = null;
        if ( channel.contains( "#" ) )
            c = new ChatChannel( channel, this );
        else
            c = new ChatUser( channel, this );
        
        chats_.add( c );
        node_.add( c.getNode() );
        
        ((RootNode) node_.getRoot()).getTree().reload();
    }
    
    public final void removeChat( String chat )
    {
        for( Chat c : chats_ )
            if( c.getName().equals( chat ) )
            {
                removeChat( c );
                return;
            }
    }
    
    public final void removeChat( Chat chat )
    {
        chats_.remove( chat );
        chat.getNode().removeFromParent();
        ((RootNode) node_.getRoot()).getTree().reload();
    }

    public final void part( String channel ) throws Exception
    {
        if( socket_ == null || socket_.isClosed() )
            throw new Exception( "You aren't connected to the server!" );

        bw_.write( "PART "
                + channel
                + "\n" );
        bw_.flush();
    }

    public void write( String message )
    {
        try
        {
            bw_.write( message + "\n" );
            bw_.flush();
        } catch ( Exception ex )
        {
            display_.print(  "Something wen't wrong while sending: " + message );
        }
    }

    public final BufferedReader getReader()
    {
        return br_;
    }

    public final BufferedWriter getWriter()
    {
        return bw_;
    }

    public final Lock getLock()
    {
        return lock_;
    }

    public final ServerDisplay getDisplay()
    {
        return display_;
    }

    public final String getName()
    {
        return host_;
    }

    public final String getCurrentNick()
    {
        return currentNick_;
    }
    
    public final DefaultMutableTreeNode getNode()
    {
        return node_;
    }

    public final void setCurrentNick( String nick )
    {
        currentNick_ = nick;
    }

    public final void handleInput( String message )
    {
        try
        {
            display_.print( message );
            bw_.write( message + "\n" );
            bw_.flush();
        }
        catch ( IOException ex )
        {
            Logger.getLogger( ServerConnection.class.getName() ).log( Level.SEVERE, null, ex );
        }
    }

    protected final void sendToChat( String channel, String msg )
    {
        for( Chat c : chats_ )
            if( c.getName().equalsIgnoreCase( channel ) )
            {
                c.print( msg );
                return;
            }
    }

    protected final void sendToAllChats( String msg )
    {
        for( Chat c : chats_ )
            c.print( msg );
    }
}
